package com.topisv.tms.service.stock.check;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.dto.ChangeInfoDto;
import com.topisv.tms.entity.stock.CusStock;
import com.topisv.tms.entity.stock.check.CheckCountTask;
import com.topisv.tms.entity.stock.check.CheckPlan;
import com.topisv.tms.entity.stock.check.CheckPlanItem;
import com.topisv.tms.entity.stock.check.CheckPlanSetting;
import com.topisv.tms.entity.stock.instorage.InstorageInfo;
import com.topisv.tms.entity.stock.instorage.OutstorageInfo;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.stock.CusStockDao;
import com.topisv.tms.repository.stock.check.CheckCountTaskDao;
import com.topisv.tms.repository.stock.check.CheckPlanDao;
import com.topisv.tms.repository.stock.check.CheckPlanItemDao;
import com.topisv.tms.repository.stock.check.CheckPlanSettingDao;
import com.topisv.tms.service.account.ShiroDbRealm.ShiroUser;
import com.topisv.tms.service.stock.CusStockService;
import com.topisv.tms.service.stock.instorage.InstorageInfoService;
import com.topisv.tms.service.stock.instorage.OutstorageInfoService;
import com.topisv.tms.utils.rule.TMSTransportRule;

@Component
@Transactional(readOnly=true)
public class CheckPlanService
{

	  @Autowired
	  private CustomersDao customersDao;
	  @Autowired
	  private AreaGroupDao areaGroupDao;
	  @Autowired
	  private UserDao userDao;
	  @Autowired
	  private InstorageInfoService instorageInfoService;
	  @Autowired
	  private OutstorageInfoService outstorageInfoService;
	  @Autowired
	  private CheckPlanDao checkPlanDao;
	  @Autowired
	  private CheckCountTaskDao checkCountTaskDao;
	  @Autowired
	  private CusStockService cusStockService;
	  @Autowired
	  private CheckPlanItemDao checkPlanItemDao;
	  @Autowired
	  private CusStockDao cusStockDao;
	  @Autowired
	  private CheckPlanSettingDao checkPlanSettingDao;

	/**
	 * 
	 * @param params 查询参数
	 * @param pageNumber 页数
	 * @param pageSize 每页条数
	 * @return
	 */
	public Page<CheckPlan> loadTask(Map<String, Object> params,int pageNumber, int pageSize) {
		Sort sort = new Sort(Sort.Direction.DESC,"id");
	    PageRequest pageRequest = new PageRequest(pageNumber-1, pageSize, sort);
	    Specification<CheckPlan> spec =this.getWhereClause(params);
	    Page<CheckPlan> page = this.checkPlanDao.findAll(spec, pageRequest);
	    List<CheckPlan> taskList=page.getContent();
	    for (CheckPlan task : taskList) {
			this.setDetail(task);
		}
	    return page;
	}
	
	/**
	 * 查询
	 * @param params 查询参数
	 * @return
	 */
	public List<CheckPlan> loadTask(Map<String, Object> params) {
	    Specification<CheckPlan> spec =this.getWhereClause(params);
	    List<CheckPlan> list = this.checkPlanDao.findAll(spec);
	    return list;
	}
	
	/**
	 * 条件封装
	 * @param params
	 * @return
	 */
	private Specification<CheckPlan> getWhereClause(final Map<String, Object> params) {
		 return new Specification<CheckPlan>(){
		    @Override
		    public Predicate toPredicate(Root<CheckPlan> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		      //customerCodes
		      String customerCodes=(String) params.get("customerCodes");
		      if(StringUtils.isNotBlank(customerCodes)){
		    	  String[] customerCodeSplit = customerCodes.split(":");
				  ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
				  int i = 0;
				  for (String _customerCode : customerCodeSplit) {
					 tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
					 i++;
				  }
				  pre.getExpressions().add(cb.or(tempCustomerCode)); 
		      }
			  
		      
		      //areagroups
		      String areagroups=(String) params.get("areagroups");
		      if(StringUtils.isNotBlank(areagroups)){
		    	  String[] areagroupSplit = areagroups.split(":");
				  ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
				  int j = 0;
				  for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("warehouseCode"), _areagroup);
						j++;
				  }
				  pre.getExpressions().add(cb.or(areagroupArray));
		      }
			  
			  
			  //customerCode
		      String customerCode=(String) params.get("customerCode");
		      if(StringUtils.isNotBlank(customerCode)){
			         pre.getExpressions().add(cb.equal(r.get("customerCode"),customerCode));
			  }
		      
		      //warehouseCode
		      String warehouseCode=(String) params.get("warehouseCode");
		      if(StringUtils.isNotBlank(warehouseCode)){
			         pre.getExpressions().add(cb.equal(r.get("warehouseCode"),warehouseCode));
			  }
		      
              //createTime
		      Date fromDate= (Date) params.get("fromDate");
		      if (fromDate != null) {
		        pre.getExpressions().add(cb.greaterThanOrEqualTo(r.<Date>get("createTime"), fromDate));
		      }
		      Date toDate= (Date) params.get("toDate");
		      if (toDate != null) {
		        pre.getExpressions().add(cb.lessThanOrEqualTo(r.<Date>get("createTime"), toDate));
		      }
		      
		      //status
		      String status=(String) params.get("status");
		      if(StringUtils.isNotBlank(status)){
		         pre.getExpressions().add(cb.equal(r.get("status"),status));
			  }
		      
		      //taskCode
		      String taskCode=(String) params.get("taskCode");
		      if(StringUtils.isNotBlank(taskCode)){
					pre.getExpressions().add(cb.equal(r.get("taskCode"),taskCode));
			  }
		      
		      return pre;
		    }
		  };
	}
	
	/**
	 * 设置属性
	 * @param task
	 */
	private void setDetail(CheckPlan task){
		
		//customer
		String customerCode=task.getCustomerCode();
		Customers customer=this.customersDao.findByCustomerCode(customerCode);
		task.setCustomer(customer);
		
		//warehouse
		String warehouseCode=task.getWarehouseCode();
		AreaGroup warehouse=this.areaGroupDao.findByGroupCode(warehouseCode);
		task.setWarehouse(warehouse);
		
		//creater
		User user=this.userDao.findByJobuuid(task.getCreaterUuid());
		task.setCreater(user);
		
	}

	/**
	 * 查询动碰信息
	 * @param customerCode
	 * @param warehouseCode
	 * @param fromDate
	 * @param toDate
	 * @return
	 */
	public List<ChangeInfoDto> queryChange(Map<String, Object> param) {
		
		List<ChangeInfoDto> changeInfoList=new ArrayList<ChangeInfoDto>();
		Map<String, ChangeInfoDto> changeInfoMap=new HashMap<String, ChangeInfoDto>();
		
		List<InstorageInfo> inInfoList=this.instorageInfoService.loadByParam(param);
		for (InstorageInfo inInfo : inInfoList) {
			String sku=inInfo.getSku();
			Integer num=inInfo.getNum();
			if(changeInfoMap.containsKey(sku)){
				ChangeInfoDto dto=changeInfoMap.get(sku);
				dto.setInNum(dto.getInNum()+num);
			}else{
				ChangeInfoDto dto=new ChangeInfoDto();
				dto.setSku(sku);
				dto.setInNum(num);
				dto.setOutNum(0);
				changeInfoMap.put(sku, dto);
				changeInfoList.add(dto);
				
			}
		}
		
		List<OutstorageInfo> outInfoList=this.outstorageInfoService.loadByParam(param);
		for (OutstorageInfo outInfo : outInfoList) {
			String sku=outInfo.getSku();
			Integer num=outInfo.getNum();
			if(changeInfoMap.containsKey(sku)){
				ChangeInfoDto dto=changeInfoMap.get(sku);
				dto.setOutNum(dto.getOutNum()+num);
			}else{
				ChangeInfoDto dto=new ChangeInfoDto();
				dto.setSku(sku);
				dto.setInNum(0);
				dto.setOutNum(num);
				changeInfoMap.put(sku, dto);
				changeInfoList.add(dto);
			}
		}
				
		return changeInfoList;
	}

	/**
	 * 创建动碰盘点计划
	 * @param customerCode
	 * @param warehouseCode
	 * @param fromDate
	 * @param toDate
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createPlanChange(String customerCode, String warehouseCode,Date fromDate, Date toDate) throws Exception {
		try {
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			Date now=new Date();
			SimpleDateFormat sdf=new SimpleDateFormat("yyMMddHHmmss");
			
			//创建盘点计划
			CheckPlan plan=new CheckPlan();
			plan.setCustomerCode(customerCode);
			plan.setWarehouseCode(warehouseCode);
			plan.setPlanCode(TMSTransportRule.generatePlanCode());
			plan.setPlanType("change");
			plan.setStatus("1");
			plan.setCreaterUuid(curUser.jobuuid);
			plan.setCreateTime(now);
			this.checkPlanDao.save(plan);
			
			//创建盘点明细
			Map<String, Object> params=new HashMap<String, Object>();
			params.put("customerCode", customerCode);
			params.put("warehouseCode", warehouseCode);
			params.put("fromDate", fromDate);
			params.put("toDate", toDate);
			List<ChangeInfoDto> changeInfoList=this.queryChange(params);
			
			List<CusStock> stockList=new ArrayList<CusStock>();
			for (ChangeInfoDto dto : changeInfoList) {
				String sku=dto.getSku();
				List<CusStock> tempList=this.cusStockService.loadStock(warehouseCode, customerCode, sku);
				stockList.addAll(tempList);
			}
			
			List<CheckPlanItem> itemList=new ArrayList<CheckPlanItem>();
			for (CusStock stock : stockList) {
				CheckPlanItem item=new CheckPlanItem();
				item.setPlanCode(plan.getPlanCode());
				item.setCustomerCode(customerCode);
				item.setWarehouseCode(warehouseCode);
				item.setSku(stock.getSku());
				item.setStockCode(stock.getStockCode());
				item.setBoxCode(stock.getBoxCode());
				item.setSalesNum(stock.getSalesNum());
				item.setUnusedNum(stock.getUnusedNum());
				item.setOrderNum(stock.getOrderNum());
				item.setLockedNum(stock.getLockedNum());
				item.setTransportNum(stock.getTransportNum());
				item.setAirNum(stock.getAirNum());
				
				item.setSalesNumCheck(stock.getSalesNum());
				item.setUnusedNumCheck(stock.getUnusedNum());
				item.setOrderNumCheck(stock.getOrderNum());
				
				itemList.add(item);
			}
			this.checkPlanItemDao.save(itemList);
			
			//创建点数任务
			CheckCountTask countTask=new CheckCountTask();
			countTask.setCustomerCode(customerCode);
			countTask.setWarehouseCode(warehouseCode);
			countTask.setPlanCode(plan.getPlanCode());
			countTask.setStatus("undo");
			countTask.setTaskCode("CC"+sdf.format(now));
			countTask.setCreateTime(now);
			this.checkCountTaskDao.save(countTask);
			
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * 创建SKU盘点计划
	 * @param customerCode
	 * @param warehouseCode
	 * @param infos_sku
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createPlanSku(String customerCode, String warehouseCode,String infos_sku) throws Exception {
		try {
			
		
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			Date now=new Date();
			
			//创建盘点计划
			CheckPlan plan=new CheckPlan();
			plan.setCustomerCode(customerCode);
			plan.setWarehouseCode(warehouseCode);
			plan.setPlanCode(TMSTransportRule.generatePlanCode());
			plan.setPlanType("sku");
			plan.setStatus("1");
			plan.setCreaterUuid(curUser.jobuuid);
			plan.setCreateTime(now);
			this.checkPlanDao.save(plan);
			
			
			List<CusStock> stockList=new ArrayList<CusStock>();
		    String[] tempArray = infos_sku.split("【;】");
		    for (String info : tempArray) {
	           String[] infoArray = info.split("【paiu】");
	           String _warehouseCode=infoArray[0];
	           String _customerCode = infoArray[1];
	           String _sku = infoArray[2];
	           List<CusStock> tempList=this.cusStockService.loadStock(_warehouseCode, _customerCode, _sku);
			   stockList.addAll(tempList);
		    }
		    
		    //创建盘点明细
		    List<CheckPlanItem> itemList=new ArrayList<CheckPlanItem>();
		    for (CusStock stock : stockList) {
				CheckPlanItem item=new CheckPlanItem();
				item.setPlanCode(plan.getPlanCode());
				item.setCustomerCode(customerCode);
				item.setWarehouseCode(warehouseCode);
				item.setSku(stock.getSku());
				item.setStockCode(stock.getStockCode());
				item.setBoxCode(stock.getBoxCode());
				item.setSalesNum(stock.getSalesNum());
				item.setUnusedNum(stock.getUnusedNum());
				item.setOrderNum(stock.getOrderNum());
				item.setLockedNum(stock.getLockedNum());
				item.setTransportNum(stock.getTransportNum());
				item.setAirNum(stock.getAirNum());
				
				item.setSalesNumCheck(stock.getSalesNum());
				item.setUnusedNumCheck(stock.getUnusedNum());
				item.setOrderNumCheck(stock.getOrderNum());
				
				itemList.add(item);
			}
			this.checkPlanItemDao.save(itemList);
			
			//创建点数任务
			CheckCountTask countTask=new CheckCountTask();
			countTask.setCustomerCode(customerCode);
			countTask.setWarehouseCode(warehouseCode);
			countTask.setPlanCode(plan.getPlanCode());
			countTask.setStatus("undo");
			countTask.setTaskCode(TMSTransportRule.generateCheckCountCode());
			countTask.setCreateTime(now);
			this.checkCountTaskDao.save(countTask);
			
		} catch (Exception e) {
			throw e;
		}	
		
	}
	
	/**
	 * 创建库位盘点
	 * @param customerCode
	 * @param warehouseCode
	 * @param infos_sku
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createPlanStock(String customerCode, String warehouseCode,String infos_stock) throws Exception {
		try {
			
			ShiroUser curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			Date now=new Date();
			
			//创建盘点计划
			CheckPlan plan=new CheckPlan();
			plan.setCustomerCode(customerCode);
			plan.setWarehouseCode(warehouseCode);
			plan.setPlanCode(TMSTransportRule.generatePlanCode());
			plan.setPlanType("stock");
			plan.setStatus("1");
			plan.setCreaterUuid(curUser.jobuuid);
			plan.setCreateTime(now);
			this.checkPlanDao.save(plan);
			
			
			List<CusStock> stockList=new ArrayList<CusStock>();
		    String[] tempArray = infos_stock.split("【;】");
		    for (String info : tempArray) {
	           String[] infoArray = info.split("【paiu】");
	//           String _customerCode = infoArray[0];
	//           String _warehouseCode=infoArray[1];
	           String _stockCode = infoArray[2];
	           List<CusStock> tempList=this.cusStockService.loadByStockCode( _stockCode);
			   stockList.addAll(tempList);
		    }
		    
		    //创建盘点明细
		    List<CheckPlanItem> itemList=new ArrayList<CheckPlanItem>();
		    for (CusStock stock : stockList) {
				CheckPlanItem item=new CheckPlanItem();
				item.setPlanCode(plan.getPlanCode());
				item.setCustomerCode(customerCode);
				item.setWarehouseCode(warehouseCode);
				item.setSku(stock.getSku());
				item.setStockCode(stock.getStockCode());
				item.setBoxCode(stock.getBoxCode());
				item.setSalesNum(stock.getSalesNum());
				item.setUnusedNum(stock.getUnusedNum());
				item.setOrderNum(stock.getOrderNum());
				item.setLockedNum(stock.getLockedNum());
				item.setTransportNum(stock.getTransportNum());
				item.setAirNum(stock.getAirNum());
				
				item.setSalesNumCheck(stock.getSalesNum());
				item.setUnusedNumCheck(stock.getUnusedNum());
				item.setOrderNumCheck(stock.getOrderNum());
				
				itemList.add(item);
			}
			this.checkPlanItemDao.save(itemList);
			
			//创建点数任务
			CheckCountTask countTask=new CheckCountTask();
			countTask.setCustomerCode(customerCode);
			countTask.setWarehouseCode(warehouseCode);
			countTask.setPlanCode(plan.getPlanCode());
			countTask.setStatus("undo");
			countTask.setTaskCode(TMSTransportRule.generateCheckCountCode());
			countTask.setCreateTime(now);
			this.checkCountTaskDao.save(countTask);
		
		} catch (Exception e) {
			throw e;
		}
		
	}
	
	
	/**
	 * 创建盘点计划——按商家
	 * @param customerCode
	 * @param warehouseCode
	 * @param planTime
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void createPlanCustomer(String customerCode, String warehouseCode,Date planTime) throws Exception {
		try {
			ShiroUser curUser = null;
			try {
				curUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
			} catch (Exception e) {

			}
			
			//创建盘点计划
			CheckPlan plan=new CheckPlan();
			plan.setCustomerCode(customerCode);
			plan.setWarehouseCode(warehouseCode);
			plan.setPlanCode(TMSTransportRule.generatePlanCode());
			plan.setPlanType("customer");
			plan.setStatus("1");
			plan.setCreaterUuid(curUser == null ? "ADMIN" : curUser.jobuuid);
			plan.setCreateTime(planTime);
			this.checkPlanDao.save(plan);
			
			
			List<CusStock> stockList=this.cusStockDao.loadStockByCustomerAndWarehouse(customerCode,warehouseCode);
		    
		    //创建盘点明细
		    List<CheckPlanItem> itemList=new ArrayList<CheckPlanItem>();
		    for (CusStock stock : stockList) {
				CheckPlanItem item=new CheckPlanItem();
				item.setPlanCode(plan.getPlanCode());
				item.setCustomerCode(customerCode);
				item.setWarehouseCode(warehouseCode);
				item.setSku(stock.getSku());
				item.setBatchCode(stock.getBatchCode());
				item.setProductDate(stock.getProductDate());
				item.setExpireDate(stock.getExpireDate());
				item.setStockCode(stock.getStockCode());
				item.setBoxCode(stock.getBoxCode());
				item.setSalesNum(stock.getSalesNum());
				item.setUnusedNum(stock.getUnusedNum());
				item.setOrderNum(stock.getOrderNum());
				item.setLockedNum(stock.getLockedNum());
				item.setTransportNum(stock.getTransportNum());
				item.setAirNum(stock.getAirNum());
				
				item.setSalesNumCheck(stock.getSalesNum());
				item.setUnusedNumCheck(stock.getUnusedNum());
				item.setOrderNumCheck(stock.getOrderNum());
				
				itemList.add(item);
			}
			this.checkPlanItemDao.save(itemList);
			
			//创建点数任务
			CheckCountTask countTask=new CheckCountTask();
			countTask.setCustomerCode(customerCode);
			countTask.setWarehouseCode(warehouseCode);
			countTask.setPlanCode(plan.getPlanCode());
			countTask.setStatus("undo");
			countTask.setTaskCode(TMSTransportRule.generateCheckCountCode());
			countTask.setCreateTime(planTime);
			this.checkCountTaskDao.save(countTask);
			
		} catch (Exception e) {
			throw e;
		}	
		
	}

	/**
	 * 定时任务：创建盘点任务
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void autoCreateCheckPlan() throws Exception {
		try {
			//三天后的日期
			Calendar calendar=Calendar.getInstance();
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			calendar.add(Calendar.DATE,3);
			Date planDate=calendar.getTime(); 
			Date toDate=calendar.getTime();
			toDate.setDate(planDate.getDate()+1);
			
			//查询是否需要创建盘点任务
			int day=calendar.get(Calendar.DATE);//三天后的号数
			List<CheckPlanSetting> settingList=(List<CheckPlanSetting>) this.checkPlanSettingDao.loadByDay(day);
			for (CheckPlanSetting setting : settingList) {
				String customerCode=setting.getCustomerCode();
				String warehouseCode=setting.getWarehouseCode();
				
			    List<CheckPlan> planList = this.checkPlanDao.loadByCondition(customerCode,warehouseCode,planDate,toDate);
				if(planList.size()==0){
                     try {
						this.createPlanCustomer(customerCode, warehouseCode, planDate);
					} catch (Exception e) {
					}
				}
			}
		} catch (Exception e) {
			throw e;
		}
			
	}

	public CheckPlan loadById(Long taskId) {
		return this.checkPlanDao.findOne(taskId);
	}

	/**
	 * 取消盘点任务
	 * @param planId
	 * @return
	 */
	@Transactional(readOnly = false)
	public String delCheckPlan(Long planId) {
		
		CheckPlan plan=this.checkPlanDao.findOne(planId);
		
		if(plan==null){
			return "noexists";
		}
		
		String status=plan.getStatus();
		if(!"1".equals(status)){
			return "cannot";
		}
		
		this.checkPlanDao.delete(plan);
		
		return "success";
	}


}